# -*- coding: utf-8 -*-
from datetime import datetime
from datetime import timedelta

from django.contrib import messages
from django.contrib.auth.decorators import user_passes_test
from django.core.mail.message import EmailMessage
from django.core.urlresolvers import reverse
from django.core import exceptions
from django.db.models import Count
from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import render_to_response, get_object_or_404
from django.template.context import RequestContext, Context
from django.template import loader

from mdcsapp.models import Match, PointsLog, MatchComment
from mdcsapp.forms import MatchForm, CommentForm
from mdcsapp import elo_utils

def matches(request, game_type):
    #danashnji mechevi
    today = datetime.today()
    game_type_id = 1
    game_name = ""
    if game_type == "chess":
        game_type_id = 1
        game_name = "šah"
    elif game_type=="table_football":
        game_type_id = 2
        game_name = "stoni fudbal"
    elif game_type=="football":
        game_type_id = 3
        game_name = "fudbal"
    elif game_type=="basketball":
        game_type_id = 4
        game_name = "basket" 
    else:
        raise Http404('Unknown game type "%s"' % game_type)
    matches = Match.objects.filter(game_type=game_type_id).filter(winner__isnull=False).order_by('-date_played')[:100]
    return render_to_response('matches/matches.html', {"matches":matches, "game_name": game_name},
        context_instance=RequestContext(request))

def match(request, match_id):
    match = get_object_or_404(Match, pk=int(match_id))
    game_name = ""
    if match.game_type == 1:
        game_name = "chess"
    elif match.game_type == 2:
        game_name = "table_football"
    elif match.game_type == 3:
        game_name = "football"
    elif match.game_type == 4:
        game_name = "basket"
    else:
        raise Http404('Unknown game type "%s"' % match.game_type)

    all_users = ",".join([",".join([str(user.id) for user in match.home.all()]), ",".join([str(user.id) for user in match.away.all()])])
    image_url = "%s?users=%s" % \
        (reverse("mdcssport.mdcsapp.views_imagegen.statistics_timeline", kwargs = {'game_type': game_name}), all_users)

    return render_to_response('matches/match.html', {"match": match, "image_url": image_url},
        context_instance=RequestContext(request))

def match_addedit_comment(request, match_id, comment_id = 0):
    match = get_object_or_404(Match, pk=int(match_id))
    comment = None
    if comment_id != 0:
        comment = get_object_or_404(MatchComment, pk=int(comment_id))

    # proveravamo privilegije rucno
    if comment == None and not request.user.has_perm('mdcsapp.add_matchcomment'):
        return HttpResponseRedirect('/mdcs/')
    if comment != None:
        if not request.user.is_superuser:
            if not (request.user.has_perm('mdcsapp.change_matchcomment') and request.user.get_profile() == comment.comment_author):
                return HttpResponseRedirect('/mdcs/')

    if request.method == 'POST':
        comment_form = CommentForm(request.POST, instance = comment)
        if comment_form.is_valid():
            if comment == None:
                inserted_comment = comment_form.save(commit = False)
                inserted_comment.comment_author = request.user.get_profile()
                inserted_comment.match = match
                inserted_comment.date_created = datetime.today()
                inserted_comment.save()
                messages.add_message(request, messages.INFO, "Komentar uspešno dodat")

                all_users = list(match.home.all()) + list(match.away.all())
                if request.user.get_profile() in all_users:
                    all_users.remove(request.user.get_profile())
                all_user_mail = [user.user.email for user in all_users if user.send_mail==True and user.user.email != ""]
                if len(all_user_mail) > 0:
                    template = loader.get_template("mail/added_comment.html")
                    message_text = template.render(Context({"comment": inserted_comment }))
                    msg = EmailMessage("[mdcs-sport] Novi komentar na meču", message_text,
                            "mdcs-sport-no-reply@sport.mdcs.rs", all_user_mail)
                    msg.content_subtype = "html"
                    msg.send(fail_silently = False)
            else:
                edited_comment = comment_form.save(commit = False)
                edited_comment.date_updated = datetime.today()
                edited_comment.save()
                messages.add_message(request, messages.INFO, "Komentar uspešno izmenjen")

            return HttpResponseRedirect(reverse(
                    "mdcssport.mdcsapp.views_matches.match", kwargs = {'match_id': match.id}))
    else:
        if comment == None:
            comment_form = CommentForm()
        else:
            comment_form = CommentForm(instance = comment)
    
    return render_to_response('matches/add_comment.html', {"match": match, "comment_id": comment_id, "comment_form": comment_form},
        context_instance=RequestContext(request))

"""
Prikazuje formu za dodavanje novog meca i dodaje mec
"""
@user_passes_test(lambda u: u.has_perm('mdcsapp.add_match'))
def add_match(request):
    if request.method == 'POST':
        form = MatchForm(request.POST)
        if form.is_valid():
            # snimamo mec
            home = form.cleaned_data['home']
            away = form.cleaned_data['away']
            # naknadno vadimo rezultat i pobednika (osecam da ovo ne treba ovde, nego negde u klasi forme)
            result = form.cleaned_data['result']
            game_type = form.cleaned_data['game_type']
            date_played = form.cleaned_data['date_played']

            # gledamo da li je mec preporucen
            today = datetime.today()
            recommended_list = Match.objects.filter(date_generated=today).filter(game_type=game_type) \
                .filter(winner__isnull=True) \
                .annotate(count_home=Count('home')).filter(count_home=len(home) * len(home)) \
                .annotate(count_away=Count('away')).filter(count_away=len(away) * len(away))
            for user in home.all():
                recommended_list = recommended_list.filter(home = user)
            for user in away.all():
                recommended_list = recommended_list.filter(away = user)

            recommended = None
            if len(recommended_list) > 0:
                recommended = recommended_list[0]

            if recommended == None:
                match = form.save(commit=False)
                match.result = result.__unicode__()
                match.winner = result.get_winner()
                match.save()
                form.save_m2m()
            else:
                recommended.date_played = date_played
                recommended.result = result.__unicode__()
                recommended.winner = result.get_winner()
                recommended.save()
                match = recommended

            # update-ujemo bodove korisnika
            home_current_sum = reduce(lambda x, y: x+y.points(match.game_type), home.all(), 0)
            away_current_sum = reduce(lambda x, y: x+y.points(match.game_type), away.all(), 0)

            home_eod_points, away_eod_points = {}, {}
            for user in home.all():
                home_eod_points[user] = get_end_of_day_points(user, match.game_type)
            for user in away.all():
                away_eod_points[user] = get_end_of_day_points(user, match.game_type)

            home_sum, away_sum = sum(home_eod_points.values()), sum(away_eod_points.values())

            offset1, offset2 = elo_utils.calculate_elo(home_sum, away_sum, result.get_winner(), recommended != None)
            offset1, offset2 = len(home.all()) * offset1, len(away.all()) * offset2
            all_points_log = []
            for user in home.all():
                # upisujemo stare poene u PointsLog
                pl1 = PointsLog()
                pl1.match = match
                pl1.user = user
                if match.game_type == 1:
                    pl1.points = user.chess_points
                elif match.game_type == 2:
                    pl1.points = user.tf_points
                elif match.game_type == 3:
                    pl1.points = user.football_points
                elif match.game_type == 4:
                    pl1.points = user.basket_points
                else:
                    raise StandardError("Unknown game type")
                pl1.save()
                all_points_log.append(pl1)

                # upisujemo nove poene u korisnika
                if match.game_type == 1:
                    user.chess_points = int(round(user.chess_points + (user.chess_points * offset1)/home_current_sum))
                elif match.game_type == 2:
                    user.tf_points = int(round(user.tf_points + (user.tf_points * offset1)/home_current_sum))
                elif match.game_type == 3:
                    user.football_points = int(round(user.football_points + (user.football_points * offset1)/home_current_sum))
                elif match.game_type == 4:
                    user.basket_points = int(round(user.basket_points + (user.basket_points * offset1)/home_current_sum))
                else:
                    raise StandardError("Unknown game type")
                user.save()
            for user in away.all():
                pl2 = PointsLog()
                pl2.match = match
                pl2.user = user
                if match.game_type == 1:
                    pl2.points = user.chess_points
                elif match.game_type == 2:
                    pl2.points = user.tf_points
                elif match.game_type == 3:
                    pl2.points = user.football_points
                elif match.game_type == 4:
                    pl2.points = user.basket_points
                else:
                    raise StandardError("Unknown game type")
                pl2.save()
                all_points_log.append(pl2)

                # upisujemo nove poene u korisnika
                if match.game_type == 1:
                    user.chess_points = int(round(user.chess_points + (user.chess_points * offset2)/away_current_sum))
                elif match.game_type == 2:
                    user.tf_points = int(round(user.tf_points + (user.tf_points * offset2)/away_current_sum))
                elif match.game_type == 3:
                    user.football_points = int(round(user.football_points + (user.football_points * offset2)/away_current_sum))
                elif match.game_type == 4:
                    user.basket_points = int(round(user.basket_points + (user.basket_points * offset2)/away_current_sum))
                else:
                    raise StandardError("Unknown game type")
                user.save()

            all_users = list(home.all()) + list(away.all())
            all_user_mail = [user.user.email for user in all_users if user.send_mail==True and user.user.email != ""]
            if len(all_user_mail) > 0:
                template = loader.get_template("mail/add_match.html")
                message_text = template.render(Context({
                    "match": match, "users": all_users, "all_points_log": all_points_log,
                    "recommended": recommended != None,
                    "user_entered": request.user.get_profile()
                }))
                msg = EmailMessage("[mdcs-sport] Meč unešen", message_text,
                        "mdcs-sport-no-reply@sport.mdcs.rs", all_user_mail)
                msg.content_subtype = "html"
                msg.send(fail_silently = False)

            # stavljamo poruku za korisnika i vracamo ga na stranu za ponovni unos
            messages.add_message(request, messages.INFO,
                    "Meč uspešno unet. Domaćini su dobili ukupno %d bodova, a gosti ukupno %d bodova." %
                    (int(round(offset1)), int(round(offset2)))
            )
            if recommended != None:
                messages.add_message(request, messages.INFO,
                    "Meč koji ste uneli je bio preporučen za danas i dobijeni poeni se razlikuju od normalnog bodovanja.")
            url_to_redirect = reverse('mdcssport.mdcsapp.views_matches.add_match')
            if 'AddContinue' in request.POST:
                url_to_redirect += "?template_match=%d" % match.id
            return HttpResponseRedirect(url_to_redirect)
    else:
        initial_form = {'date_played': datetime.today()}
        template_match_id_str = request.GET.get('template_match', '0')
        try:
            template_match_id = int(template_match_id_str)
        except exceptions.ValueError:
            template_match_id = 0
        if template_match_id != '':
            try:
                template_match = Match.objects.get(pk = int(template_match_id))
            except exceptions.ObjectDoesNotExist:
                template_match = None
            if template_match != None:
                initial_form["home"] = template_match.home.all()
                initial_form["away"] = template_match.away.all()
                initial_form["game_type"] = template_match.game_type
                initial_form["date_played"] = template_match.date_played + timedelta(minutes=1)
        form = MatchForm(initial = initial_form)
    return render_to_response('matches/add_match.html', {'form': form}, context_instance=RequestContext(request))

@user_passes_test(lambda u: u.has_perm('mdcsapp.delete_match'))
def undo_match(request, match_id):
    """
    Sklanja poslednji mec iz baze i vraca poene po starom
    """
    match = get_object_or_404(Match, pk=int(match_id))
    mail_date_played = match.date_played
    mail_game_type = match.game_type
    mail_user_points = []
    points_logs = PointsLog.objects.filter(match = match)
    # proveravamo da nema odigranih meceva posle ovog
    for user in match.home.all():
        if PointsLog.objects.filter(user = user).filter(match__game_type=match.game_type).filter(match__date_played__gte = match.date_played).exclude(match = match).count() > 0:
            messages.add_message(request, messages.INFO,
                "Meč ne može da se poništi jer je korisnik %s već igrao mečeve posle ovoga. Prvo poništite te mečeve" %
                str(user))
            return HttpResponseRedirect(reverse('mdcssport.mdcsapp.views.index'))
    for user in match.away.all():
        if PointsLog.objects.filter(user = user).filter(match__game_type=match.game_type).filter(match__date_played__gte = match.date_played).exclude(match = match).count() > 0:
            messages.add_message(request, messages.INFO,
                "Meč ne može da se poništi jer je korisnik %s već igrao mečeve posle ovoga. Prvo poništite te mečeve" %
                str(user))
            return HttpResponseRedirect(reverse('mdcssport.mdcsapp.views.index'))

    # vracamo stare poene
    home_users = list(match.home.all())
    away_users = list(match.away.all())
    for user in home_users:
        for point_log in points_logs:
            if point_log.user == user:
                if match.game_type == 1:
                    mail_user_points.append((user, user.chess_points))
                    user.chess_points = point_log.points
                elif match.game_type == 2:
                    mail_user_points.append((user, user.tf_points))
                    user.tf_points = point_log.points
                elif match.game_type == 3:
                    mail_user_points.append((user, user.football_points))
                    user.football_points = point_log.points
                elif match.game_type == 4:
                    mail_user_points.append((user, user.basket_points))
                    user.basket_points = point_log.points
                else:
                    raise StandardError("Unknown game type")
                user.save()
    for user in away_users:
        for point_log in points_logs:
            if point_log.user == user:
                if match.game_type == 1:
                    mail_user_points.append((user, user.chess_points))
                    user.chess_points = point_log.points
                elif match.game_type == 2:
                    mail_user_points.append((user, user.tf_points))
                    user.tf_points = point_log.points
                elif match.game_type == 3:
                    mail_user_points.append((user, user.football_points))
                    user.football_points = point_log.points
                elif match.game_type == 4:
                    mail_user_points.append((user, user.basket_points))
                    user.basket_points = point_log.points
                else:
                    raise StandardError("Unknown game type")
                user.save()

    # brisemo mec i logove
    points_logs.delete()
    match.delete()
    
    # gradimo poruku
    first = True
    home_string = ''
    for user in home_users:
        if not first:
            home_string += ', '
        home_string = home_string + str(user)
        first = False
    if len(home_users) > 1:
        home_string = '(' + home_string + ')'

    first = True
    away_string = ''
    for user in away_users:
        if not first:
            away_string += ', '
        away_string = away_string + str(user)
        first = False
    if len(away_users) > 1:
        away_string = '(' + away_string + ')'

    messages.add_message(request, messages.INFO, "Meč %s - %s odigran %s uspešno poništen" %
       (home_string, away_string, match.date_played.strftime('%d.%m.%Y %H:%M'))
    )

    all_user_mail = [user_point[0].user.email for user_point in mail_user_points if user_point[0].send_mail==True and user_point[0].user.email != ""]
    if len(all_user_mail) > 0:
        template = loader.get_template("mail/delete_match.html")
        message_text = template.render(Context({
            "date_played": mail_date_played,
            "game_type": mail_game_type,
            "user_points": mail_user_points,
            "user_deleted": request.user.get_profile()
        }))
        msg = EmailMessage("[mdcs-sport] Meč izbrisan", message_text,
                "mdcs-sport-no-reply@sport.mdcs.rs", all_user_mail)
        msg.content_subtype = "html"
        msg.send(fail_silently = False)
    return HttpResponseRedirect(reverse('mdcssport.mdcsapp.views.index'))

def get_end_of_day_points(user, game_type_id):
    current_points = user.points(game_type_id)
    today = datetime.today()
    end_of_day = datetime(today.year, today.month, today.day - 1, 0, 0, 0)
    pl = PointsLog.objects.filter(user = user).filter(match__game_type = game_type_id).filter(match__date_played__gte = end_of_day).order_by('match__date_played')
    if len(pl) == 0:
        return current_points
    else:
        return pl[0].points